package com.zhongying.inteceptor;

import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.NamedThreadLocal;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import com.zhongying.inteceptor.entity.RequestLogEntity;
import com.zhongying.inteceptor.util.RequestLogUtil;
import com.zhongying.sys.entity.SysMenuEntity;
import com.zhongying.sys.entity.SysUserEntity;
import com.zhongying.sys.utils.ShiroUtils;

@Aspect
public class RequestLogInteceptor extends HandlerInterceptorAdapter implements MethodInterceptor {

	private static final Logger LOGGER = LoggerFactory.getLogger(RequestLogInteceptor.class);

	private static final ThreadLocal<String> LOCAL = new NamedThreadLocal<String>("ThreadLocal Business");

	/**
	 * 在业务处理器处理请求之前被调用 如果返回false 从当前的拦截器往回执行所有拦截器的afterCompletion(),再退出拦截器链 如果返回true 执行下一个拦截器,直到所有的拦截器都执行完毕 再执行被拦截的Controller 然后进入拦截器链, 从最后一个拦截器往回执行所有的postHandle() 接着再从最后一个拦截器往回执行所有的afterCompletion()
	 */
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
		return true;
	}

	/**
	 * 在业务处理器处理请求执行完成后,生成视图之前执行的动作 可在modelAndView中加入数据，比如当前时间
	 */
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
	}

	/**
	 * 在DispatcherServlet完全处理完请求后被调用,可用于清理资源等
	 * 
	 * 当有拦截器抛出异常时,会从当前拦截器往回执行所有的拦截器的afterCompletion()
	 */
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
		SysUserEntity sysUserEntity = ShiroUtils.getUserEntity();
		RequestLogEntity requestLog = new RequestLogEntity();
		if (sysUserEntity != null) {
			// operate_url
			String uri = request.getRequestURI();
			// 静态资源
			if (uri.endsWith("css") || uri.endsWith("js") || uri.endsWith("ico")) {
				return;
			}
			// 权限判断
			if (uri.endsWith("hasPermission")) {
				return;
			}
			requestLog.setOperateUrl(uri);
			// operate_data
			Map<String, String[]> params = request.getParameterMap();
			requestLog.setOperateData(params);
			// operate_ip
			String ip = getIpAddr(request);
			requestLog.setOperateIp(ip);
			// operate_user
			Long userId = sysUserEntity.getUserId();
			requestLog.setOperateUser(String.valueOf(userId));
			// operate_business
			String menuUrl = uri;
			if (uri.startsWith("/boss/")) {
				menuUrl = uri.replaceAll("/boss/", "");
			}
			// 操作业务 识别顺序 1.菜单配置 2.权限所在菜单
			List<SysMenuEntity> list = RequestLogUtil.queryByUrl("%" + menuUrl + "%");
			if (list != null && list.size() > 0) {
				SysMenuEntity menu = list.get(0);
				String name = menu.getName();
				String parentName = menu.getParentName();
				requestLog.setOperateBusiness(parentName + "->" + name);
			} else {
				// thread local 获取
				String bus = LOCAL.get();
				if (StringUtils.isNotBlank(bus)) {
					LOCAL.remove();
					requestLog.setOperateBusiness(bus);
				}
			}
			// `operate_desc` varchar(1024) DEFAULT NULL COMMENT '操作描述备注',
			RequestLogUtil.saveLog(requestLog);
		}
	}

	public String getIpAddr(HttpServletRequest request) {
		String ipAddress = request.getHeader("x-forwarded-for");
		if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
			ipAddress = request.getHeader("Proxy-Client-IP");
		}
		if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
			ipAddress = request.getHeader("WL-Proxy-Client-IP");
		}
		if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
			ipAddress = request.getRemoteAddr();
			if (ipAddress.equals("127.0.0.1") || ipAddress.equals("0:0:0:0:0:0:0:1")) {
				// 根据网卡取本机配置的IP
				InetAddress inet = null;
				try {
					inet = InetAddress.getLocalHost();
				} catch (UnknownHostException e) {
					e.printStackTrace();
				}
				ipAddress = inet.getHostAddress();
			}
		}
		// 对于通过多个代理的情况，第一个IP为客户端真实IP,多个IP按照','分割
		if (ipAddress != null && ipAddress.length() > 15) { // "***.***.***.***".length() = 15
			if (ipAddress.indexOf(",") > 0) {
				ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
			}
		}
		return ipAddress;
	}

	@Override
	public Object invoke(MethodInvocation invocation) throws Throwable {

		Method method = invocation.getMethod();
		RequiresPermissions permissions = method.getAnnotation(RequiresPermissions.class);
		if (permissions != null) {
			String[] value = permissions.value();
			String perm = value[0];
			List<SysMenuEntity> list = RequestLogUtil.queryByPerm("%" + perm + "%");
			if (list != null && list.size() > 0) {
				SysMenuEntity menu = list.get(0);
				String name = menu.getName();
				String parentName = menu.getParentName();
				LOCAL.set(parentName + "->" + name);
			}
		}

		Object result = invocation.proceed();
		return result;
	}
}
